package docview;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Graphics;
import java.awt.GridLayout;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.ClipboardOwner;
import java.awt.dnd.DragSourceDragEvent;
import java.awt.dnd.DragSourceEvent;
import java.awt.dnd.DropTargetDragEvent;
import java.awt.dnd.DropTargetEvent;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.Vector;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.ListSelectionModel;
import javax.swing.event.TableColumnModelListener;
import javax.swing.event.TableModelEvent;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumn;
import javax.swing.table.TableModel;
import javax.swing.DropMode;
import javax.swing.TransferHandler;
import tableprocessor.Table;
import docview.ColorTable;

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

/**
 *
 * @author Dema
 */

import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.StringSelection;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.awt.dnd.DnDConstants;
import java.awt.dnd.DragGestureEvent;
import java.awt.dnd.DragGestureListener;
import java.awt.dnd.DragSource;
import java.awt.dnd.DragSourceContext;
import java.awt.dnd.DragSourceDropEvent;
import java.awt.dnd.DragSourceListener;
import java.awt.dnd.DropTarget;
import java.awt.dnd.DropTargetDropEvent;
import java.awt.dnd.DropTargetListener;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import javax.swing.JCheckBox;
import javax.swing.JCheckBoxMenuItem;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenuItem;
import javax.swing.JPopupMenu;
import javax.swing.JToolBar;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.event.TableModelListener;
import javax.swing.table.TableColumnModel;
import tableprocessor.ColumnPare;
import javax.swing.KeyStroke;
import java.util.ArrayList;
import javax.swing.JButton;



class DocTableModel extends DefaultTableModel {
    public Vector getColumnIdentifiers() {
        return columnIdentifiers;
    }
}











public class DocTable extends JPanel implements IObserver,CathegoryListener, DocTextListener{

    protected ColorTable table;
    protected JScrollPane scroller;
    protected DocTableModel tableModel;
    protected JButton addRow;
    protected JButton deleteRow;
    protected JButton addCol;
    protected JButton deleteCol;
    protected JButton connect;
    //protected ColoredTableCellRenderer tableRenderer;
    private Vector<IObserver> observers = new Vector();
    private Sender sender;
    protected JToolBar toolbar;
    protected JCheckBox checkbox;
    protected JPopupMenu popupMenu;
    protected int pointCol;


    protected DocTextListener listener = null;
    private int col = -1;
    private int row = -1;



    public void addEvent(String name) {
        if (sender == Sender.RESULT)
        {
            int[] i = table.getSelectedRows();
            if(i.length!=0)
            {
                for (int x = i[0];x<i.length; ++x)
                {
                    tableModel.setValueAt(name, x, table.getColumnCount()-1);
                }
            }
            repaint();
        }
    }
    public ColorTable getColorTable()
    {
        return table;
    }
    public void setListener(DocTextListener _listener) {
        listener = _listener;
    }

    public void notifyTextChange(String text) {
       col = table.getSelectedColumn();
       row = table.getSelectedRow();
       try
       {
       tableModel.setValueAt(text, row, col);
       }
       catch(java.lang.ArrayIndexOutOfBoundsException e)
       {}
    }

    private class DocTableListener implements ListSelectionListener,KeyListener {
            JTable jtable;
            int column = -1;
            int rowt = -1;

            private int colS = -1;
            private int colE = -1;
             private int rowS = -1;
            private int rowE = -1;

            // It is necessary to keep the table since it is not possible
            // to determine the table from the event's source
            DocTableListener(JTable table) {
                this.jtable = table;
            }
            public void valueChanged(ListSelectionEvent e) {
                // If cell selection is enabled, both row and column change events are fired
            
                    if (e.getSource() == jtable.getSelectionModel())
                    {
                        rowt = jtable.getSelectedRow();
                    }
                    if (e.getSource() == jtable.getColumnModel().getSelectionModel())
                    {
                        column = jtable.getSelectedColumn();
                    }
                    if (e.getValueIsAdjusting()) 
                        return;// The mouse button has not yet been released
                    
                    catchSelection();
                    revalidateSelection();
            }
            
            
            public void catchSelection()
            {
                if ( (rowt!= -1) && (column!= -1) )
                {
                    try
                    {
                        if (listener != null)
                        {
                            //column = jtable.getSelectedColumn();
                            //rowt = jtable.getSelectedRow();
                            try
                            {
                                Object obj = tableModel.getValueAt(rowt, column);
                                listener.notifyTextChange(obj.toString());
                            }
                            catch (java.lang.ArrayIndexOutOfBoundsException e)
                            {

                            }
                        }
                    }
                    catch(java.lang.NullPointerException e)
                    {

                    }
                }
                
            }

            public void keyTyped(KeyEvent ke) {
           // throw new UnsupportedOperationException("Not supported yet.");
        }

        public void keyPressed(KeyEvent ke) {
            int code = ke.getKeyCode();
            if ( code == ke.VK_ENTER)
            {
                if (ke.isShiftDown())
                    addColumnOnKeyStroke();
                else
                    addRowOnKeyStroke();
            }
            else if (code == ke.VK_DELETE)
            {

                
                if (ke.isShiftDown())
                    removeColumnOnKeyStroke();
                else if(ke.isControlDown())
                {
                        removeRowOnKeyStroke();
                }
                else
                {
                    if (isCoordinatsOk())
                    {
                        revalidateSelection();
                        table.setTextToSubtable(rowS, colS, rowE, colE, "");
                    }
                }
            }

        }

        private boolean isCoordinatsOk()
        {
            return (rowS!=-1 && rowE!=-1 && colS != -1 && colE !=-1);
        }

        public void keyReleased(KeyEvent ke) {
            //throw new UnsupportedOperationException("Not supported yet.");
        }

         private void revalidateSelection()
        {
            int[]rows = table.getSelectedRows();
            int[]cols = table.getSelectedColumns();
            if (rows.length > 0 && cols.length > 0 )
            {
                rowS = rows[0];
                colS = cols[0];
                rowE = rows[rows.length-1];
                colE = cols[cols.length-1];
                //System.out.println(" x = "+rowS + " y = "+colS+" w = "+rowE+" h = "+colE);
            }
        }


    }

    private class DocTableModelListener implements TableModelListener
    {

        public void tableChanged(TableModelEvent tme) {
           /* if (listener != null)
            {
                col = tme.getColumn();
                row = tme.getFirstRow();
                TableModel model = (TableModel) tme.getSource();
                if(table.isCellSelected(row, col))
                {
                    Object obj = model.getValueAt(row, col);
                    listener.notifyTextChange(obj.toString());
                }
            }*/
        }
        
    };

    private class ButtonListener implements ActionListener
    {


        public void actionPerformed(ActionEvent ae) {
            if(ae.getSource() == addRow)
            {
                Vector vec = new Vector ( tableModel.getColumnCount() );
                for (int i = 0; i< vec.size(); i++)
                    vec.add(" ");
                addNewDataRow(vec );
            }
            else if(ae.getSource() == addCol)
            {
                addColumn(String.valueOf(tableModel.getColumnCount()));
            }
            else if (ae.getSource() == deleteRow)
            {                
                removeRowOnKeyStroke();
            }
            else if(ae.getSource() == deleteCol)
            {
                removeColumnOnKeyStroke();
            }
            else if(ae.getSource() == connect)
            {

            }
        }

    }


   

     public DocTable() {
         initComponent();
     }

    public DocTable(IObserver.Sender _sender)
    {
        sender = _sender;
         initComponent();
    }

     private void initComponent() {
         tableModel = new DocTableModel();
         
         table = new ColorTable();
        
         table.setModel(tableModel);

         if (sender == Sender.RESULT)
         {
            table.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
         }
         else
             table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
         //table.setColumnSelectionAllowed(true);

         table.setRowSelectionAllowed(true);
         popupMenu = new JPopupMenu();
         JMenuItem item = new JMenuItem("Цена");
         JMenuItem item2 = new JMenuItem("Отменить");
         item.addActionListener(new ActionListener(){

            public void actionPerformed(ActionEvent ae) {
                int[] rows = table.getSelectedRows();
                table.setPriceValue(rows,pointCol);
            }

         });
         item2.addActionListener(new ActionListener(){

             public void actionPerformed(ActionEvent ae) {
                table.clearPriceValue();
            }
         });
         popupMenu.add(item);
         popupMenu.add(item2);
         MouseListener popupListener = new PopupListener();
         table.addMouseListener(popupListener);
         table.getTableHeader().addMouseListener(popupListener);
         DocTableListener listener = new DocTableListener(table);
         table.addKeyListener(listener);
         //table.setDragEnabled(true);
         //table.setDropTarget(new DropTarget(table,table));

         tableModel.addTableModelListener(new DocTableModelListener());
         table.getSelectionModel().addListSelectionListener(listener);
         table.getColumnModel().getSelectionModel().addListSelectionListener(listener);
         scroller = new javax.swing.JScrollPane(table);
         ButtonListener buttonListener = new ButtonListener();
         addRow = new JButton("Добавить строку");
         deleteRow = new JButton("Удалить строки");
         addCol = new JButton("Добавить столбец");
         deleteCol = new JButton("Удалить столбцы");
         connect = new JButton("Связать");
         addRow.addActionListener(buttonListener);
         addCol.addActionListener(buttonListener);
         deleteRow.addActionListener(buttonListener);
         deleteCol.addActionListener(buttonListener);
         connect.addActionListener(buttonListener);
         toolbar = new JToolBar();
         
         checkbox = new JCheckBox();
         checkbox.setText("Объединять ячейки");
         checkbox.addActionListener(new ActionListener(){

            public void actionPerformed(ActionEvent ae) {
                if(ae.getSource() == checkbox)
                {
                    if (checkbox.isSelected())
                        table.setMergeEnabled(true);
                    else
                        table.setMergeEnabled(false);
                }
            }
         });
         table.getTableHeader().setReorderingAllowed(false);
         toolbar.setLayout(new GridLayout(0,3));
         toolbar.add(checkbox);
         toolbar.add(addRow);
         toolbar.add(deleteRow);
         toolbar.add(new JLabel());
         
         if (sender != Sender.RESULT)
         {
             toolbar.add(addCol);
             toolbar.add(deleteCol);

             table.getTableHeader().setReorderingAllowed(true);
         }
         else
         {
             toolbar.add(connect);
         }
         setLayout(new BorderLayout());
         add(scroller, BorderLayout.CENTER);
         add(toolbar,BorderLayout.NORTH);
     }


     private  class PopupListener extends MouseAdapter {
        public void mousePressed(MouseEvent e) {
            if (e.getButton() == MouseEvent.BUTTON3)
            {
                Point pt = e.getPoint();

                //int row = table.rowAtPoint(pt);
                pointCol = table.columnAtPoint(pt);
                showPopup(e);
            }
           }

        public void mouseReleased(MouseEvent e) {
            if (e.getButton() == MouseEvent.BUTTON3)
            {
                Point pt = e.getPoint();

                //int row = table.rowAtPoint(pt);
                pointCol = table.columnAtPoint(pt);
                showPopup(e);
            }
          }

        private void showPopup(MouseEvent e) {
            if (e.isPopupTrigger()) {
                popupMenu.show(e.getComponent(), e.getX(), e.getY());
                }
        }
  }


     JToolBar getToolBar()
    {
         return toolbar;
     }

     public void addButtonActionListener(ActionListener _listener)
    {
         connect.addActionListener(_listener);
     }

     public void addSelectionListner(ListSelectionListener _listener)
    {
         table.getSelectionModel().addListSelectionListener(_listener);
         table.getColumnModel().getSelectionModel().addListSelectionListener(_listener);
     }
     public void addColumn(String text)
     {
         tableModel.addColumn(text);
         tableModel.fireTableStructureChanged();
     }

     public void addNewDataRow(Vector<String> values)
     {
         tableModel.addRow(values);
         //tableModel.fireTableStructureChanged();
     }
     public void createTable(Vector<String> headers)
     {
         Iterator<String> it = headers.iterator();
         while(it.hasNext())
         {
             addColumn(it.next());
         }
     }

    public void fillDeprecated(Iterator<Table> it)
    {
        Table t_table;
        if(it.hasNext())
        {
            t_table = it.next();
            Vector<String> headers = new Vector();
            for (int col = 0; col<t_table.getCols(0);col++)
                headers.add(t_table.getData(0, col));
           createTable(headers);
        }
        while(it.hasNext())
        {
            t_table = it.next();
            for (int row = 1; row<t_table.numRows();row++)
            {
                Vector<String> value = new Vector();
                for (int col = 0; col<t_table.getCols(row); col++ )
                    value.add(t_table.getData(row, col));

                addNewDataRow(value);
            }
        }
    }

    public void fill(Iterator<Table> it)
    {
        int maxCols = 0;
        int numRows = 0;
        if (it.hasNext())
        {
            Table t = it.next();
            numRows = t.numRows();
            for (int i =0; i<numRows; i++)
                if (t.getCols(i) > maxCols)
                    maxCols = t.getCols(i);
            for(int i =0;i < maxCols; i++)
                addColumn(String.valueOf(i+1));
            for(int i = 0; i<numRows; i++)
            {
                Vector<String> value = new Vector();
                int j;
                for(j = 0; j <t.getCols(i);j++)
                    value.add(t.getData(i, j));
                if (j<maxCols)
                    for (;j<maxCols;j++)
                        value.add(" ");
                addNewDataRow(value);
            }
        }

    }

    private void addRowOnKeyStroke()
    {
        if (table.getSelectedColumn() == table.getModel().getColumnCount()-1
                && table.getSelectedRow() == table.getModel().getRowCount()-1)
        {
            Vector vec = new Vector ( tableModel.getColumnCount() );
            for (int i = 0; i< vec.size(); i++)
                vec.add(" ");
            addNewDataRow(vec );
        }
    }

    private void removeRowOnKeyStroke()
    {
        
        if (table.getSelectedRowCount() == 1)
        {
                for (int i = 0 ; i < table.delListeners.size(); i++)
                {
                    table.delListeners.get(i).deleteRow(table.getSelectedRow(), null);
                }
            tableModel.removeRow( table.getSelectedRow() );
        }
        else
        {
            int[] mas = table.getSelectedRows();
            for (int i = mas.length -1; i >=0 ; i--)
                tableModel.removeRow( mas[i] );
        }
        tableModel.fireTableStructureChanged();
    }

    private void addColumnOnKeyStroke()
    {
       if (table.getSelectedColumn() == tableModel.getColumnCount()-1)
       {
           addColumn(String.valueOf(tableModel.getColumnCount()));
       }
    }
    public int getNumCols()
    {
        
        return table.getColumnModel().getColumnCount();
    }
    public void clearTable()
    {    
        tableModel.setColumnCount(0);
        tableModel.setRowCount(1);
    }
    public void fillPopupMenu(Iterator<ColumnPare> iter)
    {
        if (table!=null)
        {
            table.fillPopupMenu(iter);
        }
    }
    public void removeColumn(int i)
    {
        TableColumn tcolumn = table.getColumnModel().getColumn(i);
            int columnModelIndex = tcolumn.getModelIndex();
            Vector data = tableModel.getDataVector();
            Vector colIds = tableModel.getColumnIdentifiers();

            // Remove the column from the table
            table.removeColumn(tcolumn) ;

            // Remove the column header from the table model
            colIds.removeElementAt(columnModelIndex);

    // Remove the column data
            for (int r=0; r<data.size(); r++) {
                Vector row = (Vector)data.get(r);
                row.removeElementAt(columnModelIndex);
            }
            tableModel.setDataVector(data, colIds);

            // Correct the model indices in the TableColumn objects
            // by decrementing those indices that follow the deleted column
            Enumeration en = table.getColumnModel().getColumns();
            for (; en.hasMoreElements(); ) {
                TableColumn c = (TableColumn)en.nextElement();
                if (c.getModelIndex() >= columnModelIndex) {
                    c.setModelIndex(c.getModelIndex()-1);
                }
            }
            tableModel.fireTableStructureChanged();
    }

    private void removeColumnOnKeyStroke()
    {

        if (table.getSelectedColumnCount() == 1)
        {
            removeColumn(table.getSelectedColumn());
        }
        else
        {
            int[] mas = table.getSelectedColumns();
            for (int i = mas.length -1; i >=0 ; i--)
                removeColumn( mas[i] );
        }
    }

 

     public void add(int i) {
        int[] cols = table.getSelectedColumns();
        int[] rows = table.getSelectedRows();
        if ((cols.length!= 0) && (rows.length!=0))
        {
            Selection selection = new Selection(cols[0],rows[0],
                cols[cols.length-1],rows[rows.length-1]);
            createSelection(selection,sender,i);
            table.clearSelection();
        }
    }

    public void highlightOn(int i) {
       
    }

    public void highlightOff() {
        table.setSelectionData(null);
        repaint();
    }

    public void highlight(Selection one, Sender _sender) {
        if (_sender == sender)
        {
            table.setSelectionData(one);
            repaint();
        }
    }

    public void delete(int i) {
        
    }

    public void createSelection(Selection selection, Sender sender,int i) {
        Iterator<IObserver> it = observers.iterator();
        while(it.hasNext())
        {
            it.next().createSelection(selection, sender, i);
        }
    }

    public void addListener(IObserver obj) {
        observers.add(obj);
    }

    public void deleteListener(IObserver obj) {
        Iterator<IObserver> it = observers.iterator();
        while(it.hasNext())
        {
            if(it.next().equals(obj))
            {
                it.remove();
                break;
            }

        }
    }

}
